#pragma once
#include<iostream>
#include<queue>
#include<pthread.h>
#include<unistd.h>
#include<cstdlib>
using std::cin;
using std::cout;
using std::endl;
using std::queue;

const uint32_t gDefalutCap=5;
template<class T>
class blockQueue{
    public:
        blockQueue(uint32_t cap=gDefalutCap)
            :_cap(cap){
                pthread_mutex_init(&_mutex,nullptr);
                pthread_cond_init(&_SerCond,nullptr);
                pthread_cond_init(&_CreCond,nullptr);
            }
        ~blockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_SerCond);
            pthread_cond_destroy(&_CreCond);
        }
        void push(const T &in)
        {
            lockQueue();
            while(isFull())
            {
                condWait(_CreCond);
            }
            pushCore(in);
            unlockQueue();
            condWakeUp(_SerCond);
        }
        T pop()
        {
            lockQueue();
            while(isEmpty())
            {
                condWait(_SerCond);
            }
            T tmp=popCore();
            unlockQueue();
            condWakeUp(_CreCond);
            return tmp;
        }
    private:
        void lockQueue()
        {
            pthread_mutex_lock(&_mutex);
        }
        void unlockQueue()
        {
            pthread_mutex_unlock(&_mutex);
        }
        bool isEmpty()
        {
            return _bq.empty();
        }
        bool isFull()
        {
            return _bq.size()==_cap;
        }
        void condWakeUp(pthread_cond_t &cond)
        {
            pthread_cond_signal(&cond);
        }
        void condWait(pthread_cond_t &cond)
        {
            pthread_cond_wait(&cond,&_mutex);
        }
        void pushCore(const T &in)
        {
            _bq.push(in);
        }
        T popCore()
        {
            T tmp=_bq.front();
            _bq.pop();
            return tmp;
        }
    private:
        uint32_t _cap;
        queue<T> _bq;
        pthread_mutex_t _mutex;
        pthread_cond_t _SerCond;
        pthread_cond_t _CreCond;
};

